﻿using System;
using System.Collections.Specialized;
using System.Data;
using System.Data.SqlClient;

namespace Autorun
{
	[Serializable()]
	public class TaskContext : MarshalByRefObject
	{
		#region "Private members"
		private string _key;
		private int _tskId;
		private int _schId;

		private StringDictionary _parameters;
		private DateTime _plannedOn;
		private DateTime _startedOn;
		private DateTime _stoppedOn;
		private string _assemblyPath;
		private string _assemblyName;
		private string _className;
		private string _caption;
		private TaskBase _task;

		private int _exitCode;
		private Exception _error;

		private TaskContext _previousContext;
		private int _nextTaskId;
		private StringDictionary _chainedParameters;

		#endregion

		#region "Constructors"
		private TaskContext()
		{
			_key = Guid.NewGuid().ToString();
			_tskId = 0;
			_schId = 0;
			_previousContext = null;
			_nextTaskId = 0;
			_parameters = null;
			_chainedParameters = null;
			_plannedOn = DateTime.MinValue;
			_startedOn = DateTime.MinValue;
			_stoppedOn = DateTime.MaxValue;
			_assemblyPath = null;
			_assemblyName = null;
			_className = null;
			_caption = null;
			_task = null;
			_exitCode = 0;
			_error = null;
		}

		internal TaskContext(int scheduleId, int taskId, string assemblyPath, string assemblyName, string className, string caption, DateTime plannedOn, StringDictionary parameters)
		{
			_key = Guid.NewGuid().ToString();
			_tskId = taskId;
			_schId = scheduleId;
			_previousContext = null;
			_nextTaskId = 0;
			_parameters = parameters;
			_chainedParameters = null;
			_plannedOn = plannedOn;
			_startedOn = DateTime.MinValue;
			_stoppedOn = DateTime.MaxValue;
			_assemblyPath = assemblyPath;
			_assemblyName = assemblyName;
			_className = className;
			_caption = caption;
			_task = null;
			_exitCode = 0;
			_error = null;
		}

		// Create a chained context
		internal TaskContext(TaskContext previousContext)
		{
			string query;
			DataTable dt;

			query = string.Format("SELECT * FROM tblTask WHERE tskId={0}", previousContext.NextTaskId);
			dt = ExecuteDataTable(query);

			if (dt.Rows.Count == 0)
				throw new Exception(string.Format("Task #{0} does not exist.", previousContext.NextTaskId));
			else
			{
				_key = Guid.NewGuid().ToString();
				_tskId = previousContext.NextTaskId;
				_schId = 0;
				_previousContext = previousContext;
				_nextTaskId = 0;
				_parameters = ScheduleManagement.Instance.MergeTaskParameters(_tskId, _previousContext.ChainedParameters);
				_chainedParameters = null;
				_plannedOn = DateTime.MinValue;
				_startedOn = DateTime.MinValue;
				_stoppedOn = DateTime.MaxValue;
				_assemblyPath = dt.Rows[0]["tskPath"].ToString();
				_assemblyName = dt.Rows[0]["tskAssembly"].ToString();
				_className = dt.Rows[0]["tskClass"].ToString();
				_caption = dt.Rows[0]["tskCaption"].ToString();
				_task = null;
				_exitCode = 0;
				_error = null;
			}
		}

		#endregion

		#region "Properties"
		public string Caption
		{
			get { return _caption; }
		}

		public string Key
		{
			get { return string.Format("{0}{1}", _plannedOn, _key); }
		}

		public int ScheduleId
		{
			get { return _schId; }
		}

		public int TaskId
		{
			get { return _tskId; }
		}

		public int NextTaskId
		{
			get { return _nextTaskId; }
			set { _nextTaskId = value; }
		}

		public TaskContext PreviousContext
		{
			get { return _previousContext; }
		}

		public StringDictionary Parameters
		{
			get { return _parameters; }
		}

		public StringDictionary ChainedParameters
		{
			get { return _chainedParameters; }
			set { _chainedParameters = value; }
		}

		public DateTime PlannedOn
		{
			get { return _plannedOn; }
		}

		public DateTime StartedOn
		{
			get { return _startedOn; }
		}

		public DateTime StoppedOn
		{
			get { return _stoppedOn; }
		}

		public int ExitCode
		{
			get { return _exitCode; }
		}

		public Exception Error
		{
			get { return _error; }
		}

		public TaskBase Task
		{
			get { return _task; }
		}

		public string AssemblyPath
		{
			get { return _assemblyPath; }
		}

		public string AssemblyName
		{
			get { return _assemblyName; }
		}

		public string ClassName
		{
			get { return _className; }
		}
		#endregion

		#region "Procedures"
		internal void SetStartInformation()
		{
			_startedOn = DateTime.Now;
		}

		internal void SetStopInformation(int exitCode, Exception exception)
		{
			_stoppedOn = DateTime.Now;
			_exitCode = exitCode;
			_error = exception;
		}

		internal void LoadTask()
		{
			_task = IOAccessManagement.Instance.LoadTask(_assemblyPath, _assemblyName, _className);
		}
		#endregion

		#region "Data Access Methods"
		private void ExecuteNonQuery(string query)
		{
			SqlConnection cn;
			SqlCommand cmd;

			cn = new SqlConnection(Properties.Settings.Default.ConnectionString);

			try
			{
				cn.Open();
				cmd = cn.CreateCommand();
				cmd.CommandText = query;
				cmd.ExecuteNonQuery();
				cmd.Connection = null;
				cmd = null;
			}
			finally
			{
				cn.Close();
			}
		}

		private object ExecuteScalar(string query)
		{
			SqlConnection cn;
			SqlCommand cmd;
			object rc = null;

			cn = new SqlConnection(Properties.Settings.Default.ConnectionString);

			try
			{
				cn.Open();
				cmd = cn.CreateCommand();
				cmd.CommandText = query;
				rc = cmd.ExecuteScalar();
				cmd.Connection = null;
				cmd = null;
			}
			finally
			{
				cn.Close();
			}

			return rc;
		}

		private DataTable ExecuteDataTable(string query)
		{
			SqlDataAdapter da;
			DataSet rc;

			da = new SqlDataAdapter(query, Properties.Settings.Default.ConnectionString);
			rc = new DataSet();
			da.Fill(rc);
			return rc.Tables.Count != 0 ? rc.Tables[0] : null;
		}
		#endregion
	}
}
